package net.sudot.chess.business.service;

import net.sudot.chess.business.dao.OrderGameDao;
import net.sudot.chess.business.model.Customer;
import net.sudot.chess.business.model.DepositRecord;
import net.sudot.chess.business.model.OrderGame;
import net.sudot.chess.business.model.OrderLog;
import net.sudot.chess.business.model.Room;
import net.sudot.chess.business.wechat.message.ConsumeTemplateMessage;
import net.sudot.chess.business.wechat.message.EndGameTemplateMessage;
import net.sudot.chess.business.wechat.message.RefundTemplateMessage;
import net.sudot.chess.constant.LockConstants;
import net.sudot.chess.event.order.CancelledEvent;
import net.sudot.chess.event.order.CreatedEvent;
import net.sudot.commons.lock.Lock;
import net.sudot.commons.pagination.Pageable;
import net.sudot.commons.utils.SnowflakeIdWorker;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.List;

/**
 * 游戏订单
 *
 * @author tangjialin on 2018-03-21.
 */
@Service
public class OrderGameService extends BaseService<OrderGame> {
    @Resource
    private ApplicationEventPublisher applicationEventPublisher;
    @Resource(name = "orderGameServiceSnowflakeIdWorker")
    private SnowflakeIdWorker snowflakeIdWorker;
    @Resource
    private OrderGameDao orderGameDao;
    @Resource
    private OrderLogService orderLogService;
    @Resource
    private CustomerService customerService;
    @Resource
    private ConsumeTemplateMessage consumeTemplateMessage;
    @Resource
    private RefundTemplateMessage refundTemplateMessage;
    @Resource
    private EndGameTemplateMessage endGameTemplateMessage;

    /**
     * 获取游戏订单信息
     *
     * @param sn 订单编号
     * @return 返回订单信息
     */
    public OrderGame findBySn(String sn) {
        return orderGameDao.find("sn", sn);
    }

    /**
     * 获取订单列表
     *
     * @param page       分页参数
     * @param customerId 客户主键
     * @return 返回订单列表
     */
    public List<OrderGame> findList(Pageable page, Long customerId) {
        return orderGameDao.findList(page, customerId);
    }

    /**
     * 获取游戏订单信息
     *
     * @param roomId     房间主键
     * @param customerId 客户信息
     * @return 返回游戏订单信息
     */
    public OrderGame findUnComplete(Long roomId, Long customerId) {
        return orderGameDao.findUnComplete(roomId, customerId);
    }

    /**
     * 获取未完成的游戏订单信息
     *
     * @param roomId 房间主键
     * @return 返回订单信息
     */
    public List<OrderGame> findListUnComplete(Long roomId) {
        return orderGameDao.findListUnComplete(roomId);
    }

    /**
     * 创建游戏订单
     *
     * @param room     房间
     * @param customer 游戏玩家
     * @return 返回创建的游戏订单
     */
    @Transactional(rollbackFor = Exception.class)
    public OrderGame create(Room room, Customer customer) {
        BigDecimal price = room.getPrice();
        OrderGame order = new OrderGame();
        order.setUserId(customer.getId());
        order.setTarget(room.getId());
        order.setGameId(room.getGameId());
        order.setSn(snowflakeIdWorker.getStringId());
        order.setStatus(OrderGame.Status.PAID);
        order.setPrice(price);
        order.setPaymentAmount(price);
        order.setPaidAmount(price);
        order.setRefundAmount(BigDecimal.ZERO);
        order.setExchangeAmount(BigDecimal.ZERO);
        order.setExchangePoint(0L);
        order.setIsExchangeAmount(false);
        order.setIsExchangePoint(false);
        order.setMemo(String.format("[第%s期]%s【%s】", room.getPeriod(), room.getName(), room.getRegion()));
        order = save(order);

        OrderLog orderLog = new OrderLog();
        orderLog.setType(OrderLog.Type.PAYMENT);
        orderLog.setOrderId(order.getId());
        orderLogService.save(orderLog);

        customer = customerService.find(customer.getId());
        customerService.addBalance(customer, price.negate(), DepositRecord.Type.GAME, order.getMemo());

        applicationEventPublisher.publishEvent(new CreatedEvent<OrderGame>(this, order, customer));
        consumeTemplateMessage.send(customer, order);
        return order;
    }

    /**
     * 取消订单
     *
     * @param order 取消的订单
     */
    @Lock(name = LockConstants.ORDER_GAME, value = "#order.id")
    @Transactional(rollbackFor = Exception.class)
    public void cancel(OrderGame order) {
        if (order.getStatus() != OrderGame.Status.PAID) { return; }
        order.setStatus(OrderGame.Status.CANCELED);
        update(order);
        BigDecimal refundableAmount = order.getRefundableAmount();
        if (refundableAmount.compareTo(BigDecimal.ZERO) <= 0) { return; }

        OrderLog orderLog = new OrderLog();
        orderLog.setType(OrderLog.Type.CANCEL);
        orderLog.setOrderId(order.getId());
        orderLogService.save(orderLog);

        Customer customer = customerService.find(order.getUserId());
        customerService.addBalance(customer, refundableAmount, DepositRecord.Type.GAME, order.getMemo());

        applicationEventPublisher.publishEvent(new CancelledEvent<OrderGame>(this, order, customer));
        refundTemplateMessage.send(customer, order);
    }

    /**
     * 完成订单
     *
     * @param order 订单
     */
    @Lock(name = LockConstants.ORDER_GAME, value = "#order.id")
    @Transactional(rollbackFor = Exception.class)
    public void complete(OrderGame order) {
        if (order.getStatus() != OrderGame.Status.PAID) { return; }
        order.setStatus(OrderGame.Status.COMPLETED);
        order.setCompleteDate(Instant.now());

        OrderLog orderLog = new OrderLog();
        orderLog.setType(OrderLog.Type.COMPLETE);
        orderLog.setOrderId(order.getId());
        orderLogService.save(orderLog);

        Customer customer = customerService.find(order.getUserId());
        applicationEventPublisher.publishEvent(new CancelledEvent<OrderGame>(this, order, customer));
        endGameTemplateMessage.send(customer, order);
    }

}
